package reflect;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 通过反射调用一个类的方法
 */
public class MethodTest {
    public static void main(String[] args) throws Exception {
        // 1.要使用反射，需要获取该类的Class对象
        Class<?> cls = Class.forName("reflect.Student");
        // 2.获取该类的所有方法的Method对象
        // 2.1 获取private的eat方法对象
        // cls.getDeclareMethod(方法名称，方法的参数类型)
        Method methodEat = cls.getDeclaredMethod("eat");
        methodEat.setAccessible(true); // 破坏封装
        // eat方法是Student的成员方法，必须通过Student类的对象来调用
        // 所以先获取该类的实例化对象
        Student stu = (Student) cls.newInstance();
        // 这样就可以开始调用该方法了
        // 方法对象名.invoke(通过那个具体对象来调用，方法的参数)
        methodEat.invoke(stu); // 这里没有参数就不写了 结果：Person类的无参构造方法 Student类的无参构造方法 He is eating

        // 2.2 获取静态方法的对象
        Method staticFunc = cls.getDeclaredMethod("staticFunc");
        // 调用静态方法不需要实例对象
        staticFunc.invoke(null); // 填null就好 结果：静态方法

        // 3.获取当前类以及其父类的所有public方法
        // Class对象.getMethod()
        Method pubFunc = cls.getMethod("sleep");
        // sleep是成员方法需要实例调用
        Student stu1 = (Student) cls.newInstance();
        pubFunc.invoke(stu1); // 结果：Person类的无参构造方法 Student类的无参构造方法 He is a pig
        Method praFunc = cls.getMethod("play"); // 成员方法
        praFunc.invoke(stu1); // public func
        // 注意仅仅是只能看到父类的public方法而已，并不能拿到父类的Class对象，所以破坏分装也无法拿到父类的private方法
//        Method praFuncPrivate = cls.getMethod("happy");
//        praFuncPrivate.setAccessible(true);
//        praFuncPrivate.invoke(stu1); // 报错


        // 4.获取当前类的所有方法集合，包括private方法
        // cls.getDeclaredMethods()
        Method[] allMethod = cls.getDeclaredMethods();
        System.out.println(Arrays.toString(allMethod)); // 结果：[public java.lang.String reflect.Student.toString(), public void reflect.Student.sleep(), private void reflect.Student.function(java.lang.String), public static void reflect.Student.staticFunc(), private void reflect.Student.eat()]
    }
}
